package cn.net.yugu.doraemon.netty.msg;

import cn.net.yugu.doraemon.netty.factory.msg.MessageFactory;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;

import java.util.List;
import java.util.UUID;

/**
 * @description:
 * @author: wanghongli
 * @create: 2022-07-12 13:55:22
 */
@Slf4j
public class MessageDecoder extends ByteToMessageDecoder {
    private static final String TRACE_ID = "traceId";
    private MessageFactory messageFactory;
    public MessageDecoder(MessageFactory messageFactory) {
        this.messageFactory = messageFactory;
    }

    @Override
    protected void decode(ChannelHandlerContext context, ByteBuf buf, List<Object> list) throws Exception {
        if (StringUtils.isBlank(MDC.get(TRACE_ID))) {
            MDC.put(TRACE_ID, UUID.randomUUID().toString().replace("-", "").toLowerCase());
        }
        if(log.isDebugEnabled()) {
            buf.markReaderIndex();
            byte[] bytes = new byte[buf.readableBytes()];
            buf.readBytes(bytes);
            log.debug("from {} recv hex: {}", context.channel().remoteAddress(), new String(Hex.encodeHex(bytes)));

            buf.resetReaderIndex();
        }

        int beginReaderIndex = buf.readerIndex(), beginReadableBytes = buf.readableBytes();
        buf.markReaderIndex();
        if(buf.readableBytes() >= 12) {
            int msgCode = buf.readInt(); //msgCode

            if(msgCode / 1000000 == 11 || msgCode / 1000000 == 61 || msgCode == 72000005 || msgCode == 72000006 || msgCode == 72000007 || msgCode == 72000008 || msgCode == 81000013 || msgCode == 81000015 || msgCode == 81000017  || msgCode == 241000002 || msgCode == 71000011 ){
                if(buf.readableBytes() >= 12){
                    buf.readInt();//时间戳
                }else{
                    buf.resetReaderIndex();
                    return;
                }
            }

            buf.readInt(); //searial number

            int length = buf.readInt();
            if(msgCode == 81000006 || msgCode == 81000013 || msgCode == 81000014 || msgCode == 81000015  || msgCode == 81000017   || msgCode == 71000011) {
                buf.readShort();
            }
            if(buf.readableBytes() >= length) { // ok
                if (log.isDebugEnabled()) {
                    log.debug("message code:{}", msgCode);
                }
                Class<? extends Message> clazz = messageFactory.getClass(msgCode);
                if(clazz == null) {
                    if(log.isWarnEnabled()) {
                        log.warn("Not recognition message code: {}", msgCode);
                    }
                } else {
                    buf.resetReaderIndex();
                    Message message = clazz.newInstance();

                    try {
                        message.decode(buf);
                    } catch (Exception e) {
                        dumpHex(buf, beginReaderIndex, beginReadableBytes);
                        throw e;
                    }

                    if (message.warn_info != null) {
                        log.error("decode_warn_info: {}", message.warn_info);
                        dumpHex(buf, beginReaderIndex, beginReadableBytes);
                    }

                    list.add(message);
                }

            } else {
                buf.resetReaderIndex();
            }
        } else {
            buf.resetReaderIndex();
        }
    }

    private void dumpHex(ByteBuf buf, int beginReaderIndex, int beginReadableBytes) {
        log.error("decode error, start dump hex");

        byte[] bytes = new byte[beginReadableBytes];
        buf.getBytes(beginReaderIndex, bytes);

        log.error("decode error, dump hex: {}", Hex.encodeHexString(bytes));
    }
}
